/*
 * Copyright 2013-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.cloud.gateway.filter;

import java.net.URI;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import reactor.core.publisher.Mono;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.core.Ordered;
import org.springframework.web.reactive.DispatcherHandler;
import org.springframework.web.server.ServerWebExchange;

import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.handle;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.isAlreadyRouted;

/**
 * 1. 什么是 ForwardRoutingFilter？
 * 作用：
 * 		ForwardRoutingFilter 专门用于处理目标 URI 使用 forward: 前缀的路由。
 * 		它通过将请求转发到本地路径来实现内部资源的访问，而不需要经过网络层。
 * 典型场景：
 * 		在网关中定义某些路径直接映射到本地的静态资源或控制器。
 * 		比如，将 /local-resource 路径的请求转发到本地的 /internal/resource。
 */
public class ForwardRoutingFilter implements GlobalFilter, Ordered {

	private static final Log log = LogFactory.getLog(ForwardRoutingFilter.class);

	private final ObjectProvider<DispatcherHandler> dispatcherHandlerProvider;

	// do not use this dispatcherHandler directly, use getDispatcherHandler() instead.
	private volatile DispatcherHandler dispatcherHandler;

	public ForwardRoutingFilter(ObjectProvider<DispatcherHandler> dispatcherHandlerProvider) {
		this.dispatcherHandlerProvider = dispatcherHandlerProvider;
	}

	private DispatcherHandler getDispatcherHandler() {
		if (dispatcherHandler == null) {
			dispatcherHandler = dispatcherHandlerProvider.getIfAvailable();
		}

		return dispatcherHandler;
	}

	@Override
	public int getOrder() {
		return Ordered.LOWEST_PRECEDENCE;
	}

	/**
	 * 此函数是Spring Cloud Gateway项目中的一个过滤器方法，用于处理网关服务的路由逻辑。
	 * 在Spring Cloud Gateway中，过滤器可以用于修改请求和响应，或者根据特定条件执行特定的逻辑。
	 * 此函数主要处理“forward”协议的路由逻辑。
	 * 首先，函数通过exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR)获取请求URL，并解析其协议（scheme）。
	 * 接着，检查是否已经路由过或者协议的方案（scheme）不是“forward”，如果满足条件，则直接通过调用chain.filter(exchange)继续过滤器链的后续处理，不进行特殊逻辑。
	 * 如果协议的方案是“forward”，代码进入到待实现的URL转换逻辑部分（当前以TODO注释标记）。在这一部分，如果启用了跟踪日志（trace log），则会记录要转发的URI。
	 * 最后，如果满足转发条件，则调用handle(this.getDispatcherHandler(), exchange)方法处理请求，该方法可能会根据URI将请求转发到相应的处理器。
	 * 整体而言，此函数的作用是在网关服务的过滤器链中，根据请求的URI协议方案，决定是否进行特殊的路由处理或者继续执行后续的过滤器。这在网关服务中是一个关键的功能，因为它允许根据请求的特性（如协议类型）动态地调整路由逻辑，从而实现灵活的请求处理机制。
	 * 在具体的业务场景中，此函数与其他系统组件的交互主要体现在：
	 *
	 * 作为网关服务的一部分，此函数与路由谓词处理、限流、度量指标等功能模块协同工作，共同实现对请求的高效、灵活处理。
	 * 在测试场景中，ForwardRoutingFilterTests中的多个测试方法验证了此函数在不同条件下的行为，确保其功能按预期工作。
	 *
	 * 此函数的重要性在于它使得Spring Cloud Gateway能够根据请求的特性（如URI的协议方案）执行不同的路由策略，从而支持复杂的路由需求，在微服务架构中实现请求的智能分发和处理
	 * @param exchange the current server exchange
	 * @param chain provides a way to delegate to the next filter
	 * @return
	 */
	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);

		String scheme = requestUrl.getScheme();
		if (isAlreadyRouted(exchange) || !"forward".equals(scheme)) {
			return chain.filter(exchange);
		}

		// TODO: translate url?

		if (log.isTraceEnabled()) {
			log.trace("Forwarding to URI: " + requestUrl);
		}

		return handle(this.getDispatcherHandler(), exchange);
	}

}
